# coding: utf-8
from typing import Dict, Callable, Union

from PySide6.QtCore import Qt
from PySide6.QtGui import QFont, QIcon
from PySide6.QtWidgets import QWidget, QButtonGroup, QVBoxLayout
from qfluentwidgets import PushButton, ScrollArea, NavigationItemPosition, FluentIconBase, MSFluentWindow
from qfluentwidgets.components.navigation.navigation_panel import RouteKeyError

from common import StyleSheet


class NavigationButton(PushButton):
    def _postInit(self):
        self.setFixedHeight(45)
        self.setCheckable(True)
        StyleSheet.Navigation.apply(self)


class NavigationBar(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.items = {}  # type: Dict[str, QWidget]
        self.buttonGroup = QButtonGroup(self)
        self.scrollArea = ScrollArea(self)
        self.scrollWidget = QWidget()

        self.vBoxLayout = QVBoxLayout(self)
        self.topLayout = QVBoxLayout()
        self.bottomLayout = QVBoxLayout()
        self.scrollLayout = QVBoxLayout(self.scrollWidget)
        self.__initWidget()

    def __initWidget(self):
        self.setFixedWidth(180)
        self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground)
        self.window().installEventFilter(self)

        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.scrollArea.horizontalScrollBar().setEnabled(False)
        self.scrollArea.setWidget(self.scrollWidget)
        self.scrollArea.setWidgetResizable(True)

        self.scrollWidget.setObjectName('scrollWidget')
        self.scrollArea.enableTransparentBackground()
        self.__initLayout()

    def __initLayout(self):
        self.vBoxLayout.setContentsMargins(20, 5, 20, 5)
        self.topLayout.setContentsMargins(4, 0, 4, 0)
        self.bottomLayout.setContentsMargins(4, 0, 4, 0)
        self.scrollLayout.setContentsMargins(4, 0, 4, 0)
        self.vBoxLayout.setSpacing(4)
        self.topLayout.setSpacing(4)
        self.bottomLayout.setSpacing(4)
        self.scrollLayout.setSpacing(4)

        self.vBoxLayout.addLayout(self.topLayout, 0)
        self.vBoxLayout.addWidget(self.scrollArea)
        self.vBoxLayout.addLayout(self.bottomLayout, 0)

        self.vBoxLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.topLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.scrollLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.bottomLayout.setAlignment(Qt.AlignmentFlag.AlignBottom)


    def widget(self, routeKey: str):
        if routeKey not in self.items:
            raise RouteKeyError(f"`{routeKey}` is illegal.")

        return self.items[routeKey]

    def addItem(
            self,
            routeKey: str,
            icon: Union[str, QIcon, FluentIconBase],
            text: str,
            onClick=None,
            position=NavigationItemPosition.TOP
    ):
        """ add navigation item

        Parameters
        ----------
        routeKey: str
            the unique name of item

        icon: str | QIcon | FluentIconBase
            the icon of navigation item

        text: str
            the text of navigation item

        onClick: callable
            the slot connected to item clicked signal

        position: NavigationItemPosition
            where the button is added
        """
        return self.insertItem(-1, routeKey, icon, text, onClick, position)

    def addWidget(self, routeKey: str, widget: QWidget, onClick=None, position=NavigationItemPosition.TOP):
        """ 添加自定义小部件

        Parameters
        ----------
        routeKey: str
            the unique name of item

        widget: NavigationWidget
            the custom widget to be added

        onClick: callable
            the slot connected to item clicked signal

        position: NavigationItemPosition
            where the button is added
        """
        self.insertWidget(-1, routeKey, widget, onClick, position)

    def insertItem(
            self,
            index: int,
            routeKey: str,
            icon: Union[str, QIcon, FluentIconBase],
            text: str,
            onClick=None,
            position=NavigationItemPosition.TOP
    ):
        """ 插入导航树项

        Parameters
        ----------
        index: int
            the insert position of parent widget

        routeKey: str
            the unique name of item

        icon: str | QIcon | FluentIconBase
            the icon of navigation item

        text: str
            the text of navigation item

        onClick: callable
            the slot connected to item clicked signal

        position: NavigationItemPosition
            where the button is added
        """
        if routeKey in self.items:
            return

        w = NavigationButton(icon, text, self)
        self.insertWidget(index, routeKey, w, onClick, position)
        self.buttonGroup.addButton(w)
        return w

    def insertWidget(
            self,
            index: int,
            routeKey: str,
            widget: QWidget,
            onClick=None,
            position=NavigationItemPosition.TOP
    ):
        """ 插入自定义小部件

        Parameters
        ----------
        index: int
            insert position

        routeKey: str
            the unique name of item

        widget: NavigationWidget
            the custom widget to be added

        onClick: callable
            the slot connected to item clicked signal

        position: NavigationItemPosition
            where the button is added
        """
        if routeKey in self.items:
            return

        self._registerWidget(routeKey, widget, onClick)
        self._insertWidgetToLayout(index, widget, position)

    def _registerWidget(self, routeKey: str, widget: QWidget, onClick: Callable = None):
        """ register widget """
        if hasattr(widget, 'clicked'):
            if onClick is not None:
                widget.clicked.connect(onClick)

        widget.setProperty('routeKey', routeKey)
        self.items[routeKey] = widget

    def _insertWidgetToLayout(self, index: int, widget: QWidget, position: NavigationItemPosition):
        """ 向布局插入小部件 """
        if position == NavigationItemPosition.TOP:
            widget.setParent(self)
            self.topLayout.insertWidget(index, widget, 0, Qt.AlignmentFlag.AlignTop)
        elif position == NavigationItemPosition.SCROLL:
            widget.setParent(self.scrollWidget)
            self.scrollLayout.insertWidget(index, widget, 0, Qt.AlignmentFlag.AlignTop)
        else:
            widget.setParent(self)
            self.bottomLayout.insertWidget(index, widget, 0, Qt.AlignmentFlag.AlignBottom)

        widget.show()

    def buttons(self):
        return self.buttonGroup.buttons()

    def removeWidget(self, routeKey: str):
        """ remove widget

        Parameters
        ----------
        routeKey: str
            the unique name of item
        """
        if routeKey not in self.items:
            return

        widget = self.items.pop(routeKey)
        if isinstance(widget, NavigationButton):
            self.buttonGroup.removeButton(widget)
        widget.deleteLater()

    def setFont(self, font: QFont):
        """ 设置导航项的字体 """
        super().setFont(font)

        for widget in self.buttons():
            widget.setFont(font)

    def setCurrentItem(self, routeKey: str):
        """ 设置当前选中的项目

        Parameters
        ----------
        routeKey: str
            the unique name of item
        """
        if routeKey not in self.items:
            return
        widget = self.items[routeKey]
        if isinstance(widget, NavigationButton):
            widget.setChecked(True)
